package lv.solcraft.replication.client.boot;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.util.Assert;

/**
 * Booter is responsible for starting configured replication clients.
 * <p>
 * It reads configuration from REPLICATION_HOME/replication-client/clients.xml
 * file, parses it and then starts configured clients. One client startup
 * failure will fail whole booting.
 * <p>
 * REPLICATION_HOME can be set directly via <code>replication.home</code> system
 * property.
 * <p>
 * Lifecycle methods <code>start</code> and <code>stop</code> are executed from
 * Spring application context (<code>applicationContext-boot.xml</code>).
 * 
 * @author Ilgvars
 */
public class Booter {

    private static Logger log = Logger.getLogger(Booter.class);

    private final Map<String, Client> clients = new HashMap<String, Client>();

    private final StartupOptions startupOptions;

    public Booter(StartupOptions startupOptions) {
        this.startupOptions = startupOptions;
    }

    public void start() throws Exception {
        log.info("Starting replication clients");
        configureRestletLogging();
        log.info("Encoding " + System.getProperty("file.encoding"));
        Assert.isTrue("UTF-8".equals(System.getProperty("file.encoding")), "file.encoding must be UTF-8");
        String clientsHome = startupOptions.getReplHome() + "/clients";
        log.info("Replication client home: " + clientsHome);
        File homeDir = new File(clientsHome);
        Assert.isTrue(homeDir.exists(), "Replication home dir not found: " + homeDir.getAbsolutePath());
        Assert.isTrue(homeDir.isDirectory(), "Replication home dir is not actually a directory: "
                + homeDir.getAbsolutePath());
        startClients(startupOptions.getReplHome(), clientsHome);
        log.info("Replication clients started");
    }

    private void configureRestletLogging() {
        java.util.logging.Logger.getLogger("com.noelios").setLevel(Level.SEVERE);
        java.util.logging.Logger.getLogger("org.restlet").setLevel(Level.SEVERE);
    }

    @SuppressWarnings("unchecked")
    protected void startClients(String replHome, String clientsHome) throws Exception {
        File clientsHomeFile = new File(clientsHome);
        Collection<File> clientXmls = FileUtils.listFiles(clientsHomeFile, new String[] { "client.xml" }, false);
        for (File file : clientXmls) {
            ClientBootConfig clientConfig = ClientBootConfig.fromXML(file);
            clientConfig.setReplHome(new File(replHome));
            Client client = new Client(clientConfig);
            clients.put(client.getConfig().getClientName(), client);
        }
    }

    public void stop() throws Exception {
        log.info("Stopping replication clients");
        stopClients();
        log.info("Stopped replication clients");
    }

    protected void stopClients() {
        for (Client client : clients.values()) {
            try {
                client.stop();
            } catch (Exception e) {
                log.warn("Error while stopping replication client: " + client.getConfig().getClientName(), e);
            }
        }
    }

    public Client getClient(String name) {
        Client client = clients.get(name);
        Assert.notNull(client, "Client not configured or started, client name: " + client);
        return client;
    }
}
